/*
 * Copyright (c) 2025 Huawei Device, Inc. Ltd. and <马弓手>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Globalization.h"
#include "cJSON.h"
#include <unicode/uloc.h>
#include <unicode/ustring.h>
#include <unicode/udat.h>
#include <unicode/ucal.h>

REGISTER_PLUGIN_CLASS(Globalization)
bool Globalization::execute(const string&  action, cJSON* args, CallbackContext cbc)
{
    if(action == "getLocalName") {
        string strRet = getPreferredLanguage();
        cJSON* pObj = cJSON_CreateObject();
        cJSON_AddStringToObject(pObj, "value", strRet.c_str());
        cbc.success(pObj);
        cJSON_Delete(pObj);
    } else if(action == "getPreferredLanguage") {
        string strRet = getPreferredLanguage();
        cJSON* pObj = cJSON_CreateObject();
        cJSON_AddStringToObject(pObj, "value", strRet.c_str());
        cbc.success(pObj);
        cJSON_Delete(pObj);
    }else if(action == "dateToString") {
        dateToString(args, cbc);
    } else if(action == "stringToDate") {
        stringToDate(args, cbc);
    } else if(action == "getDatePattern") {
        getDatePattern(args, cbc);
    } else if(action == "getDateNames") {
        getDateNames(args, cbc);
    } else if(action == "isDayLightSavingsTime") {
        isDayLightSavingsTime(args, cbc);
    } else if(action == "getFirstDayOfWeek") {
        getFirstDayOfWeek(args, cbc);
    } else if(action == "numberToString") {
        numberToString(args, cbc);
    } else if(action == "stringToNumber") {
        stringToNumber(args, cbc);
    } else if(action == "getNumberPattern") {
        getNumberPattern(args, cbc);
    } else if(action == "getCurrencyPattern") {
        getCurrencyPattern(args, cbc);
    } 
    return true;
}

string Globalization::getPreferredLanguage()
{
    UErrorCode status = U_ZERO_ERROR;
    const char* currentLocale = uloc_getDefault(); // 如 "zh_CN" 或 "en_US"
    
    // 提取语言和国家代码（不去掉国家部分）
    char language[ULOC_LANG_CAPACITY] = {0};
    char country[ULOC_COUNTRY_CAPACITY] = {0};
    
    uloc_getLanguage(currentLocale, language, sizeof(language), &status);
    if (U_FAILURE(status)) return currentLocale;
    
    uloc_getCountry(currentLocale, country, sizeof(country), &status);
    
    // 组合为 language-COUNTRY 格式（如 zh-CN）
    std::string result(language);
    if (country[0] != '\0') {
        result += "-";
        result += country;
    }
    
    return result;
}

string Globalization::getLocaleName()
{
    UErrorCode status = U_ZERO_ERROR;
    // 1. 获取当前系统语言环境
    const char* currentLocale = uloc_getDefault();
    
    // 2. 获取基础语言代码（去掉国家/地区部分）
    char baseLang[ULOC_LANG_CAPACITY] = {0};
    uloc_getLanguage(currentLocale, baseLang, sizeof(baseLang), &status);
    if (U_FAILURE(status)) 
        return currentLocale;

    // 3. 使用当前语言环境作为显示语言
    UChar displayName[256];
    int32_t length = uloc_getDisplayLanguage(
        baseLang,        // 要显示的语言代码
        currentLocale,   // 使用当前系统语言环境显示
        displayName,     // 输出缓冲区
        sizeof(displayName)/sizeof(UChar),
        &status
    );
    
    // 4. 转换为UTF-8字符串
    if (U_SUCCESS(status) && length > 0) {
        char* result = (char*)malloc(length * 4 + 1);
        u_strToUTF8(
            result, 
            length*4+1, 
            NULL,
            displayName, 
            length,
            &status
        );
        if (U_SUCCESS(status)) {
            string ret = result;
            free(result);
            return ret;
        }
        free(result);
    }
    
    // 失败时返回语言代码
    return baseLang;
}

void Globalization::getFirstDayOfWeek(cJSON* pOpt, CallbackContext cbc)
{
    UErrorCode status = U_ZERO_ERROR;
    
    // 1. 创建日历实例（使用默认区域设置）
    UCalendar* cal = ucal_open(
        NULL, 0,                // 使用时区
        uloc_getDefault(),      // 当前locale
        UCAL_DEFAULT,           // 默认日历类型
        &status
    );
    
    if (U_FAILURE(status)) {
        cbc.error("Failed to create calendar");
        return;
    }

    // 2. 获取一周的第一天（UCAL_SUNDAY=1, UCAL_MONDAY=2,...）
    int firstDay = ucal_getAttribute(cal, UCAL_FIRST_DAY_OF_WEEK);
    
    // 3. 转换为ISO标准（1=Monday, 7=Sunday）
    int isoFirstDay;
    switch (firstDay) {
        case UCAL_SUNDAY:    isoFirstDay = 7; break;
        case UCAL_MONDAY:    isoFirstDay = 1; break;
        case UCAL_TUESDAY:   isoFirstDay = 2; break;
        case UCAL_WEDNESDAY: isoFirstDay = 3; break;
        case UCAL_THURSDAY:  isoFirstDay = 4; break;
        case UCAL_FRIDAY:    isoFirstDay = 5; break;
        case UCAL_SATURDAY:  isoFirstDay = 6; break;
        default:             isoFirstDay = 1; // 默认周一
    }
    
    // 5. 清理资源
    ucal_close(cal);

    cJSON* pRet = cJSON_CreateObject();
    cJSON_AddNumberToObject(pRet, "value", isoFirstDay);
    cbc.success(pRet);
    cJSON_Delete(pRet);
}
void Globalization::isDayLightSavingsTime(cJSON* pOpt, CallbackContext cbc)
{
    if(cJSON_GetArraySize(pOpt) < 1) {
        cbc.error("Invalid arguments");
        return;
    }
    cJSON* pObj = cJSON_GetArrayItem(pOpt, 0);
    long timestamp = cJSON_GetObjectItem(pObj, "date")->valuedouble;
    
    UErrorCode status = U_ZERO_ERROR;
    
    UCalendar* cal = ucal_open(
        NULL, 0, // 默认时区
        uloc_getDefault(), // 当前locale
        UCAL_DEFAULT, 
        &status
    );
    
    if (U_FAILURE(status)) {
        cbc.error("Calendar creation failed");
        return;
    }
    
    ucal_setMillis(cal, (UDate)timestamp, &status);
    
    bool isLight = ucal_inDaylightTime(cal, &status);
    
    cJSON* pRet = cJSON_CreateObject();
    if(isLight) {
        cJSON_AddTrueToObject(pRet, "dst");
    } else {
        cJSON_AddFalseToObject(pRet, "dst");
    }
    cbc.success(pRet);
    cJSON_Delete(pRet);
}
void Globalization::dateToString(cJSON* pOpt, CallbackContext cbc)
{
    if(cJSON_GetArraySize(pOpt) < 1) {
        cbc.error("Invalid arguments");
        return;
    }
    cJSON* pObj = cJSON_GetArrayItem(pOpt, 0);
    long timestamp = cJSON_GetObjectItem(pObj, "date")->valuedouble;
    cJSON* pOption = cJSON_GetObjectItem(pObj, "options");
    UDateFormatStyle dateStyle, timeStyle;
    dateStyle = UDAT_SHORT;
    timeStyle = UDAT_SHORT;
    cJSON* pFormatLength = cJSON_GetObjectItem(pOption, "formatLength");
    if(pFormatLength != nullptr) {
        string formatLength = pFormatLength->valuestring;
        if(strcasecmp(formatLength.c_str(),"medium") == 0) {
            dateStyle = UDAT_MEDIUM;
            timeStyle = UDAT_MEDIUM;
        } else if(strcasecmp(formatLength.c_str(),"long") == 0) {
            dateStyle = UDAT_LONG;
            timeStyle = UDAT_LONG;
        } else if(strcasecmp(formatLength.c_str(),"full") == 0) {
            dateStyle = UDAT_FULL;
            timeStyle = UDAT_FULL;
        }
    }
    cJSON* pSelector = cJSON_GetObjectItem(pOption, "selector");
    if(pSelector != nullptr) {
        string selector = pSelector->valuestring;
        if(strcasecmp(selector.c_str(), "date") == 0) {
            timeStyle = UDAT_NONE;
        } else if(strcasecmp(selector.c_str(), "time") == 0) {
            dateStyle = UDAT_NONE;
        }
    }
    
    UErrorCode status = U_ZERO_ERROR;
    // 1. 转换时间戳（毫秒->秒）
    if (timestamp < 0) {
        cbc.error("Formatter creation failed");
        return;
    }

    // 2. 获取系统默认locale
    const char* locale = uloc_getDefault();
    
    // 3. 创建日期格式化器
    UDateFormat* dfmt = udat_open(
        timeStyle,
        dateStyle,
        locale,
        NULL,
        0,
        NULL,
        0,
        &status
    );

    if (U_FAILURE(status)) {
        cbc.error("Formatter creation failed");
        return;
    }

    // 4. 格式化日期
    UChar ustr[256];
    int32_t length = udat_format(
        dfmt,
        (UDate)timestamp,  // ICU使用毫秒时间戳
        ustr,
        sizeof(ustr)/sizeof(UChar),
        NULL,
        &status
    );
    
    // 5. 清理资源
    udat_close(dfmt);
    
    // 6. 处理结果
    if (U_SUCCESS(status)) {
        // 转换为UTF-8
        char buffer[512];
        u_strToUTF8(
            buffer,
            sizeof(buffer),
            NULL,
            ustr,
            length,
            &status
        );

        if (U_SUCCESS(status)) {
            cJSON* pRet = cJSON_CreateObject();
            cJSON_AddStringToObject(pRet, "value", buffer);
            cbc.success(pRet);
            cJSON_Delete(pRet);
        } 
    }
}

void Globalization::stringToDate(cJSON* pOpt, CallbackContext cbc)
{
    if(cJSON_GetArraySize(pOpt) < 1) {
        cbc.error("Invalid arguments");
        return;
    }
    cJSON* pObj = cJSON_GetArrayItem(pOpt, 0);
    string strDate = cJSON_GetObjectItem(pObj, "dateString")->valuestring;
    cJSON* pOption = cJSON_GetObjectItem(pObj, "options");
    UDateFormatStyle dateStyle, timeStyle;
    dateStyle = UDAT_SHORT;
    timeStyle = UDAT_SHORT;
    
    cJSON* pSelector = cJSON_GetObjectItem(pOption, "selector");
    if(pSelector != nullptr) {
        string selector = pSelector->valuestring;
        if(strcasecmp(selector.c_str(), "date") == 0) {
            timeStyle = UDAT_NONE;
        } else if(strcasecmp(selector.c_str(), "time") == 0) {
            dateStyle = UDAT_NONE;
        }
    }
    
    UErrorCode status = U_ZERO_ERROR;
    const char* locale = uloc_getDefault();
    UDateFormat* dfmt = udat_open(
        timeStyle,
        dateStyle,
        locale,
        NULL,
        0,
        NULL,
        0,
        &status
    );

    if (U_FAILURE(status)) {
        cbc.error("Formatter creation failed");
        return;
    }
    
    // 2. 将输入字符串转换为UChar（UTF-16）
    UChar ustr[256];
    int32_t ustrLen = 0;
    u_strFromUTF8(
        ustr, 
        sizeof(ustr)/sizeof(UChar),
        &ustrLen,
        strDate.c_str(),
        -1, // 自动计算源字符串长度
        &status
    );
    
    if (U_FAILURE(status)) {
        cbc.error("Error converting");
        udat_close(dfmt);
        return;
    }

    int nResult= 0;
    UDate parsedDate = udat_parse(
        dfmt,
        ustr,
        ustrLen,
        &nResult,
        &status
    );
    
    if (U_FAILURE(status)) {
        cbc.error("Error converting");
        udat_close(dfmt);
        return;
    }
    udat_close(dfmt);
    time_t t = (time_t)(parsedDate / 1000);
    struct tm * pTm = localtime(&t);
    
    cJSON* pRet = cJSON_CreateObject();
    cJSON_AddNumberToObject(pRet, "year", pTm->tm_year+1900);
    cJSON_AddNumberToObject(pRet, "month", pTm->tm_mon+1);
    cJSON_AddNumberToObject(pRet, "day", pTm->tm_mday);
    cJSON_AddNumberToObject(pRet, "hour", pTm->tm_hour);
    cJSON_AddNumberToObject(pRet, "minute", pTm->tm_min);
    cJSON_AddNumberToObject(pRet, "second", pTm->tm_sec);
    cJSON_AddNumberToObject(pRet, "millsecond", 0);
    cbc.success(pRet);
    cJSON_Delete(pRet);
}

void Globalization::getDateNames(cJSON* pOpt, CallbackContext cbc)
{
    if(cJSON_GetArraySize(pOpt) < 1) {
        cbc.error("Invalid arguments");
        return;
    }
    cJSON* pObj = cJSON_GetArrayItem(pOpt, 0);
    cJSON* pOption = cJSON_GetObjectItem(pObj, "options");
    UDateFormatStyle dateStyle = UDAT_LONG;
    int nItem = 0;
    cJSON* pType = cJSON_GetObjectItem(pOption, "type");
    if(pType != nullptr) {
        string strType = pType->valuestring;
        if(strcasecmp(strType.c_str(),"narrow") == 0) {
            dateStyle = UDAT_SHORT;
        }
    }
    cJSON* pItem = cJSON_GetObjectItem(pOption, "item");
    if(pItem != nullptr) {
        string strItem = pItem->valuestring;
        if(strcasecmp(strItem.c_str(), "days") == 0) {
            nItem += 10;
        } 
    }
    
    
    UErrorCode status = U_ZERO_ERROR;
    const char* locale = uloc_getDefault();
    
    // 2. 创建格式化器用于获取名称
    UDateFormat* dfmt = udat_open(
        dateStyle,
        dateStyle, // 不关心日期时间格式
        locale,
        NULL, 0, NULL, 0,
        &status
    );
    
    if (U_FAILURE(status)) {
        cbc.error("Failed to create formatter");
        return;
    }

    // 3. 准备结果数组
    vector<string> vecNames; // 月份需要13个元素（1-12）
    int count = (nItem == 10) ? 7 : 12;
    
    // 4. 获取名称
    for (int i = 0; i < count; i++) {
        int32_t index = (nItem == 10) ? i + 1 : i; // 日从1开始，月从0开始
        UChar ustr[50];
        
        int nMaxLength = 0;
        if (nItem == 10) {
            nMaxLength = udat_getSymbols(dfmt, UDAT_WEEKDAYS, index, ustr, 50, &status);
        } else {
            nMaxLength = udat_getSymbols(dfmt, UDAT_MONTHS, index, ustr, 50, &status);
        }
        
        if (U_SUCCESS(status)) {
            string strName = ustrToUtf8(ustr, nMaxLength); // -1表示自动计算长度
            vecNames.push_back(strName);
        } else {
            break;
        }
    }
    udat_close(dfmt);
    
    const char* szName[vecNames.size()];
    for(int i=0; i<vecNames.size(); i++) {
        szName[i] = vecNames[i].c_str();
    }
    cJSON* pArray = cJSON_CreateStringArray(szName, vecNames.size());
    cJSON* pRet = cJSON_CreateObject();
    cJSON_AddItemToObject(pRet, "value", pArray);
    cbc.success(pRet);
    cJSON_Delete(pRet);
}
void Globalization::numberToString(cJSON* pOpt, CallbackContext cbc)
{
    if(cJSON_GetArraySize(pOpt) < 1) {
        cbc.error("Invalid arguments");
        return;
    }
    cJSON* pObj = cJSON_GetArrayItem(pOpt, 0);
    cJSON* pNumber = cJSON_GetObjectItem(pObj, "number");
    cJSON* pOption = cJSON_GetObjectItem(pObj, "options");
    string strType = "";
    cJSON* pType = cJSON_GetObjectItem(pOption, "type");
    if(pType != nullptr) {
        strType = pType->valuestring;
    }
    bool isInt = false;
    cJSON* pIsInt = cJSON_GetObjectItem(pOption, "isInt");
    if(pIsInt != nullptr) {
        if(pIsInt->type == cJSON_True) {
            isInt = true;
        }
    }
    UNumberFormatStyle style = UNUM_DECIMAL;
    if(strcasecmp(strType.c_str(), "currency") == 0) {
        style = UNUM_CURRENCY;
    } else if(strcasecmp(strType.c_str(), "present") == 0) {
        style = UNUM_PERCENT;
    }
    
    UErrorCode status = U_ZERO_ERROR;
    const char* locale = uloc_getDefault();
    
    UNumberFormat* numfmt = unum_open(
        style,
        NULL, 0,
        locale,
        NULL,
        &status
    );
    
    if (U_FAILURE(status)) {
        cbc.error("unum_open failed");
        return;
    }

    // 2. 格式化数字
    UChar ustr[256];
    int32_t len;
    if (isInt) {
        long number = pNumber->valuedouble;
        len = unum_formatInt64(
            numfmt,
            (int64_t)number,
            ustr,
            sizeof(ustr)/sizeof(UChar),
            NULL,
            &status
        );
    } else {
        double number = pNumber->valuedouble;
        len = unum_formatDouble(
            numfmt,
            number,
            ustr,
            sizeof(ustr)/sizeof(UChar),
            NULL,
            &status
        );
    }
    
    unum_close(numfmt);
    if (U_FAILURE(status)) {
        cbc.error("Number formatting failed");
        return;
    }
    string strResult = ustrToUtf8(ustr, len);
    cJSON* pRet = cJSON_CreateObject();
    cJSON_AddStringToObject(pRet, "value", strResult.c_str());
    cbc.success(pRet);
    cJSON_Delete(pRet);
}
void Globalization::stringToNumber(cJSON* pOpt, CallbackContext cbc)
{
    if(cJSON_GetArraySize(pOpt) < 1) {
        cbc.error("Invalid arguments");
        return;
    }
    cJSON* pObj = cJSON_GetArrayItem(pOpt, 0);
    cJSON* pNumber = cJSON_GetObjectItem(pObj, "numberString");
    string numberString;
    if(pNumber != nullptr) {
        numberString = pNumber->valuestring;
    }
    cJSON* pOption = cJSON_GetObjectItem(pObj, "options");
    string strType = "";
    cJSON* pType = cJSON_GetObjectItem(pOption, "type");
    if(pType != nullptr) {
        strType = pType->valuestring;
    }
    
    UNumberFormatStyle style = UNUM_DECIMAL;
    if(strcasecmp(strType.c_str(), "currency") == 0) {
        style = UNUM_CURRENCY;
    } else if(strcasecmp(strType.c_str(), "present") == 0) {
        style = UNUM_PERCENT;
    }
    
    UErrorCode status = U_ZERO_ERROR;
    const char* locale = uloc_getDefault();
    
    // 1. 创建数字格式化器（用于解析）
    UNumberFormat* numfmt = unum_open(
        style,
        NULL, 0,
        locale,
        NULL,
        &status
    );
    
    if (U_FAILURE(status)) {
        cbc.error("unum_open failed");
        return;
    }
    
    // 2. 转换输入字符串为UChar（UTF-16）
    UChar ustr[256];
    int32_t ustrLen = 0;
    u_strFromUTF8(
        ustr, 
        sizeof(ustr)/sizeof(UChar),
        &ustrLen,
        numberString.c_str(),
        numberString.length(), // 自动计算源字符串长度
        &status
    );
    
    if (U_FAILURE(status)) {
        unum_close(numfmt);
        cbc.error("Invalid string encoding");
        return;
    }

    // 3. 解析数字
    double result = 0;
    int32_t parsePos = 0;
    result = unum_parseDouble(
        numfmt,
        ustr,
        ustrLen,
        &parsePos, // 返回解析结束位置
        &status
    );
    unum_close(numfmt);
    
    cJSON* pRet = cJSON_CreateObject();
    cJSON_AddNumberToObject(pRet, "value", result);
    cbc.success(pRet);
    cJSON_Delete(pRet);
}
void Globalization::getNumberPattern(cJSON* pOpt, CallbackContext cbc)
{
    if(cJSON_GetArraySize(pOpt) < 1) {
        cbc.error("Invalid arguments");
        return;
    }
    cJSON* pObj = cJSON_GetArrayItem(pOpt, 0);
    cJSON* pOption = cJSON_GetObjectItem(pObj, "options");
    string strType = "";
    cJSON* pType = cJSON_GetObjectItem(pOption, "type");
    if(pType != nullptr) {
        strType = pType->valuestring;
    }
    UNumberFormatStyle style = UNUM_DECIMAL;
    if(strcasecmp(strType.c_str(), "currency") == 0) {
        style = UNUM_CURRENCY;
    } else if(strcasecmp(strType.c_str(), "present") == 0) {
        style = UNUM_PERCENT;
    }
    
    UErrorCode status = U_ZERO_ERROR;
    const char* locale = uloc_getDefault();
    UNumberFormat* numfmt = unum_open(
        style,
        NULL, 0,
        locale,
        NULL,
        &status
    );
    
    if (U_FAILURE(status)) {
        cbc.error("unum_open failed");
        return;
    }

    // 2. 获取格式模式
    UChar upattern[256];
    int32_t patLen = unum_toPattern(
        numfmt,
        FALSE, // 不本地化模式符号
        upattern,
        sizeof(upattern)/sizeof(UChar),
        &status
    );
     if (U_FAILURE(status)) {
        unum_close(numfmt);
        cbc.error("unum_toPattern failed");
        return;
    }
    
    string pattern = ustrToUtf8(upattern, patLen);
    
    // 3. 获取符号
    UChar symbol[256];
    int symbolLen = unum_getSymbol(
        numfmt, 
        (style == UNUM_CURRENCY) ? UNUM_CURRENCY_SYMBOL :
        (style == UNUM_PERCENT)  ? UNUM_PERCENT_SYMBOL  :
                             UNUM_PLUS_SIGN_SYMBOL,
        symbol,
        sizeof(symbol)/sizeof(UChar),
        &status
    );
    string strSymbol = ustrToUtf8(symbol, symbolLen);
    
    int32_t maxFrac = unum_getAttribute(numfmt, UNUM_MAX_FRACTION_DIGITS);
    double roundingIncrement = unum_getDoubleAttribute(numfmt, UNUM_ROUNDING_INCREMENT);
    
    UChar udecimal[256];
    int decLen = unum_getSymbol(numfmt, UNUM_DECIMAL_SEPARATOR_SYMBOL, udecimal, sizeof(udecimal)/sizeof(UChar),&status);
    string strDec = ustrToUtf8(udecimal, decLen);
     if (U_FAILURE(status)) {
        unum_close(numfmt);
        cbc.error("unum_getSymbol failed");
        return;
    }
    
    UChar ugrouping[256];
    int groupLen = unum_getSymbol(numfmt, UNUM_GROUPING_SEPARATOR_SYMBOL, ugrouping, sizeof(ugrouping)/sizeof(UChar),&status);
    string strGroup = ustrToUtf8(ugrouping, groupLen);
     if (U_FAILURE(status)) {
        unum_close(numfmt);
        cbc.error("unum_getSymbol failed");
        return;
    }
    
    UChar uplusSign[256];
    int plusLen = unum_getSymbol(numfmt, UNUM_PLUS_SIGN_SYMBOL, uplusSign, sizeof(ugrouping)/sizeof(UChar),&status);
    string strPlus = ustrToUtf8(uplusSign, plusLen);
     if (U_FAILURE(status)) {
        unum_close(numfmt);
        cbc.error("unum_getSymbol failed");
        return;
    }
    
    UChar uminusSign[256];
    int minusLen = unum_getSymbol(numfmt, UNUM_MINUS_SIGN_SYMBOL, uminusSign, sizeof(uminusSign)/sizeof(UChar),&status);
    string strMinus = ustrToUtf8(uminusSign, minusLen);
     if (U_FAILURE(status)) {
        unum_close(numfmt);
        cbc.error("unum_getSymbol failed");
        return;
    }
    
    unum_close(numfmt);
    
    cJSON* pRet = cJSON_CreateObject();
    cJSON_AddStringToObject(pRet, "pattern", pattern.c_str());
    cJSON_AddStringToObject(pRet, "symbol", strSymbol.c_str());
    cJSON_AddNumberToObject(pRet, "fraction", maxFrac);
    cJSON_AddNumberToObject(pRet, "rounding", roundingIncrement);
    cJSON_AddStringToObject(pRet, "positive", strPlus.c_str());
    cJSON_AddStringToObject(pRet, "negative", strMinus.c_str());
    cJSON_AddStringToObject(pRet, "decimal", strDec.c_str());
    cJSON_AddStringToObject(pRet, "grouping", strGroup.c_str());
    cbc.success(pRet);
    cJSON_Delete(pRet);
    
}

void Globalization::getCurrencyPattern(cJSON* pOpt, CallbackContext cbc)
{
     if(cJSON_GetArraySize(pOpt) < 1) {
        cbc.error("Invalid arguments");
        return;
    }
    cJSON* pObj = cJSON_GetArrayItem(pOpt, 0);
    cJSON* pOption = cJSON_GetObjectItem(pObj, "currencyCode");
    string strCurCode = "";
    if(pOption != nullptr) {
        strCurCode = pOption->valuestring;
    }
    UErrorCode status = U_ZERO_ERROR;
    
    UNumberFormat* numfmt = unum_open(
        UNUM_CURRENCY,
        NULL, 0,
        uloc_getDefault(),
        NULL,
        &status
    );
    
    UChar upattern[256];
    int32_t patLen = unum_toPattern(
        numfmt,
        FALSE, // 不本地化模式符号
        upattern,
        sizeof(upattern)/sizeof(UChar),
        &status
    );
    
    string  strPattern = ustrToUtf8(upattern, patLen);
    
    UChar udecimal, ugrouping;
    unum_getSymbol(numfmt, UNUM_DECIMAL_SEPARATOR_SYMBOL, &udecimal, 1, &status);
    unum_getSymbol(numfmt, UNUM_GROUPING_SEPARATOR_SYMBOL, &ugrouping, 1, &status);
    
    int maxFrac = unum_getAttribute(numfmt, UNUM_MAX_FRACTION_DIGITS);
    cJSON* pRet = cJSON_CreateObject();
    cJSON_AddStringToObject(pRet, "pattern", strPattern.c_str());
    cJSON_AddStringToObject(pRet, "code", strCurCode.c_str());
    cJSON_AddNumberToObject(pRet, "fraction", maxFrac);
    cJSON_AddNumberToObject(pRet, "rounding", 0);
    char szBuf[32];
    sprintf(szBuf, "%c", udecimal);
    cJSON_AddStringToObject(pRet, "decimal", szBuf);
    sprintf(szBuf, "%c", ugrouping);
    cJSON_AddStringToObject(pRet, "grouping", szBuf);
    cbc.success(pRet);
    cJSON_Delete(pRet);
}
void Globalization::getDatePattern(cJSON* pOpt, CallbackContext cbc)
{
    if(cJSON_GetArraySize(pOpt) < 1) {
        cbc.error("Invalid arguments");
        return;
    }
    cJSON* pObj = cJSON_GetArrayItem(pOpt, 0);
    cJSON* pOption = cJSON_GetObjectItem(pObj, "options");
    UDateFormatStyle dateStyle, timeStyle;
    dateStyle = UDAT_SHORT;
    timeStyle = UDAT_SHORT;
    cJSON* pFormatLength = cJSON_GetObjectItem(pOption, "formatLength");
    if(pFormatLength != nullptr) {
        string formatLength = pFormatLength->valuestring;
        if(strcasecmp(formatLength.c_str(),"medium") == 0) {
            dateStyle = UDAT_MEDIUM;
            timeStyle = UDAT_MEDIUM;
        } else if(strcasecmp(formatLength.c_str(),"long") == 0) {
            dateStyle = UDAT_LONG;
            timeStyle = UDAT_LONG;
        } else if(strcasecmp(formatLength.c_str(),"full") == 0) {
            dateStyle = UDAT_FULL;
            timeStyle = UDAT_FULL;
        }
    }
    cJSON* pSelector = cJSON_GetObjectItem(pOption, "selector");
    if(pSelector != nullptr) {
        string selector = pSelector->valuestring;
        if(strcasecmp(selector.c_str(), "date") == 0) {
            timeStyle = UDAT_NONE;
        } else if(strcasecmp(selector.c_str(), "time") == 0) {
            dateStyle = UDAT_NONE;
        }
    }
    
    UErrorCode status = U_ZERO_ERROR;
    // 2. 获取系统默认locale
    const char* locale = uloc_getDefault();
    
    // 3. 创建日期格式化器
    UDateFormat* dfmt = udat_open(
        timeStyle,
        dateStyle,
        locale,
        NULL,
        0,
        NULL,
        0,
        &status
    );

    if (U_FAILURE(status)) {
        cbc.error("udat_open failed");
        return;
    }
    
    UChar pattern[256];
    int32_t patLen = udat_toPattern(dfmt, FALSE, pattern, 256, &status);
    udat_close(dfmt);
    if (U_FAILURE(status)) {
        cbc.error("udat_toPattern failed");
        return;
    }
    string strPatter = ustrToUtf8(pattern, patLen);
    
    UCalendar* cal = ucal_open(NULL, 0, uloc_getDefault(), UCAL_DEFAULT, &status);
    if (U_FAILURE(status)) {
        cbc.error("ucal_open failed");
        return;
    }
    
    int32_t tzIdLen = 256;
    UChar tzId[tzIdLen];
    int nMaxLength = ucal_getTimeZoneID(cal, tzId, tzIdLen, &status);
    if(nMaxLength > tzIdLen || U_FAILURE(status)) {
        cbc.error("ucal_getTimeZoneID failed");
        return;
    }
    string strTzId = ustrToUtf8(tzId, nMaxLength);
    
    int32_t tzNameLen = 256;
    UChar tzName[tzNameLen];
    nMaxLength = ucal_getTimeZoneDisplayName(cal, UCAL_STANDARD, uloc_getDefault(), tzName, tzNameLen, &status);
    if(nMaxLength > tzNameLen || U_FAILURE(status)) {
        cbc.error("ucal_getTimeZoneDisplayName failed");
        return;
    }
    
    string strTzName = ustrToUtf8(tzName, nMaxLength);
    
    int nRawOffset = ucal_get(cal, UCAL_ZONE_OFFSET,  &status);
    int nDstOffset = ucal_get(cal, UCAL_DST_OFFSET,  &status);
    ucal_close(cal);
    
    cJSON* pRet = cJSON_CreateObject();
    cJSON_AddStringToObject(pRet, "pattern", strPatter.c_str());
    cJSON_AddStringToObject(pRet, "timezone", strTzName.c_str());
    cJSON_AddStringToObject(pRet, "iana_timezone", strTzId.c_str());
    cJSON_AddNumberToObject(pRet, "utf_offset", nRawOffset);
    cJSON_AddNumberToObject(pRet, "dst_offset", nDstOffset);
    cbc.success(pRet);
    cJSON_Delete(pRet);
}

string Globalization::ustrToUtf8(const UChar* ustr, int32_t len) 
{
    string strBuf;
    char* buf = (char*)malloc(len * 4 + 1);
    UErrorCode status = U_ZERO_ERROR;
    u_strToUTF8(buf, len * 4 + 1, NULL, ustr, len, &status);
    if(U_SUCCESS(status)) {
        strBuf = buf;
    }
    free(buf);
    return strBuf;
}